use std::collections::HashSet;
use std::hash::{Hash, Hasher};
use chrono::{DateTime, Local};
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use crate::db::pojo::pojo::{ImMessage, ImMessageActionStatus, ImMessageFileStatus, ImMessageRefType, ImMessageStatus, MessageType};
use crate::business::websocket::dto::user_dto::TerminalType;
use crate::business::websocket::dto::json_serialize::{date_time_serde, date_time_serde_null};

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct MessagePullBySessionIdsReq {

    #[serde(rename = "startServerMessageId")]
    pub start_server_message_id: Option<String>,

    #[serde(rename = "pageSize")]
    pub page_size: usize,

    #[serde(rename = "sessionIds")]
    pub session_ids: HashSet<String>,

    #[serde(rename = "terminalType")]
    pub terminal_type: TerminalType,

    #[serde(rename = "aftDate", with = "date_time_serde_null")]
    pub aft_date: Option<DateTime<Local>>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct MessageObjectList {
    #[serde(rename = "messageObjectList")]
    pub message_object_list: Vec<MessageObject>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct MessageObject {

    #[serde(rename = "messageType")]
    pub message_type: MessageType,

    #[serde(rename = "fromUserId")]
    pub from_user_id: String,

    pub content: String,

    #[serde(rename = "serverId")]
    pub server_id: Option<String>,

    #[serde(rename = "sessionId")]
    pub session_id: Option<String>,

    #[serde(rename = "groupCode")]
    pub group_code: Option<String>,

    #[serde(rename = "toUserId")]
    pub to_user_id: Option<String>,

    #[serde(rename = "refType")]
    pub ref_type: Option<MessageRefType>,

    #[serde(rename = "refMessageIds")]
    pub ref_message_ids: Option<String>,
    pub status: MessageStatus,

    #[serde(rename = "fileStatus")]
    pub file_status: Option<MessageFileStatus>,

    #[serde(rename = "actionStatus")]
    pub action_status: MessageActionStatus,

    #[serde(rename = "userSendInfoSet")]
    pub user_send_info_set: Option<HashSet<MessageUserSendInfo>>,

    #[serde(rename = "createDateTime", with = "date_time_serde")]
    pub create_date_time: DateTime<Local>,

    #[serde(rename = "localSeq")]
    pub local_seq: String,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct MessageUserSendInfo {

    #[serde(rename = "userId")]
    pub user_id: String,

    pub status: MessageStatus,

    #[serde(rename = "actionStatus")]
    pub action_status: MessageActionStatus,

    #[serde(rename = "fileStatus")]
    pub file_status: MessageFileStatus,
}

impl Hash for MessageUserSendInfo {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        self.user_id.hash(hasher);
    }
}

impl PartialEq<Self> for MessageUserSendInfo {
    fn eq(&self, other: &Self) -> bool {
        self.user_id == other.user_id
    }
}

impl Eq for MessageUserSendInfo {}

#[derive(Debug, Deserialize, Serialize)]
pub struct OkListReq {

    #[serde(rename = "localSeqSet")]
    pub local_seq_set: HashSet<String>,

    pub coder: i16,

    #[serde(rename = "otherInfo")]
    pub other_info: Option<String>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct MessagePullActionReq {

    #[serde(rename = "serverMessageId")]
    pub server_message_id: Option<String>,

    pub size: usize,

    #[serde(rename = "aftDate", with = "date_time_serde_null")]
    pub aft_date: Option<DateTime<Local>>,

    #[serde(rename = "createDateTime", with = "date_time_serde")]
    pub create_date_time: DateTime<Local>,

    #[serde(rename = "localSeq")]
    pub local_seq: String,
}


#[derive(Debug, Deserialize, Serialize)]
pub struct MessageActionList {

    #[serde(rename = "messageActionItemList")]
    pub message_action_item_list: Vec<MessageActionItem>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct MessageActionItem {

    #[serde(rename = "messageId")]
    pub message_id: String,

    #[serde(rename = "userId")]
    pub user_id: String,

    #[serde(rename = "messageActionStatus")]
    pub message_action_status: String,

    pub r#type: MessageActionType,
}


#[derive(Debug, Deserialize, Serialize)]
pub struct MessagePullActionOkReq {

    #[serde(rename = "messageActionOkItemList")]
    pub message_action_ok_item_list: Vec<MessageActionOkItem>,

    #[serde(rename = "createDateTime", with = "date_time_serde")]
    pub create_date_time: DateTime<Local>,

    #[serde(rename = "localSeq")]
    pub local_seq: String,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct MessageActionOkItem {

    #[serde(rename = "messageId")]
    pub message_id: String,

    #[serde(rename = "userId")]
    pub user_id: String,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct MessagePullByMessageIdsReq {

    #[serde(rename = "serverMessageIdList")]
    pub server_message_id_list: Vec<String>,

    #[serde(rename = "createDateTime", with = "date_time_serde")]
    pub create_date_time: DateTime<Local>,

    #[serde(rename = "localSeq")]
    pub local_seq: String,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct MessageObjectsReq {

    #[serde(rename = "messageObjects")]
    pub message_objects: Vec<MessageObject>,

    #[serde(rename = "createDateTime", with = "date_time_serde")]
    pub create_date_time: DateTime<Local>,

    #[serde(rename = "localSeq")]
    pub local_seq: String,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct MessageReadReq {

    #[serde(rename = "messageIds")]
    pub message_ids: HashSet<String>,

    #[serde(rename = "createDateTime", with = "date_time_serde")]
    pub create_date_time: DateTime<Local>,

    #[serde(rename = "localSeq")]
    pub local_seq: Option<String>,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct MessageWithdrawReq {

    #[serde(rename = "messageIds")]
    pub message_ids: HashSet<String>,

    #[serde(rename = "createDateTime", with = "date_time_serde")]
    pub create_date_time: DateTime<Local>,

    #[serde(rename = "localSeq")]
    pub local_seq: Option<String>,
}







#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum MessageRefType {
    Ref = 1,
    Transfer = 2,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum MessageStatus {
    None = 0,
    Receive = 1,
    Readed = 2,
    Withdrawed = 3,
    Delete = 4,
    Updated = 5,
    UserDelete = 6,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum MessageFileStatus {
    None = 0,
    Uploaded = 1,
    Downloading = 2,
    Downloaded = 3,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum MessageActionStatus {
    None = 0,
    Readed = 1,
    Withdrawed = 2,
    Delete = 3,
    Updated = 4,
    UserDelete = 5,
}

#[derive(Debug, Clone, Serialize_repr, Deserialize_repr, PartialEq)]
#[repr(u8)]
pub enum MessageActionType {
    Owner = 1,
    Other = 2,
}

impl Into<ImMessage> for MessageObject {
    fn into(self) -> ImMessage {
        //todo
        ImMessage {
            id: None,
            client_id: self.server_id.clone().unwrap(),
            from_user_id: self.from_user_id,
            current_user_id: "".to_string(),
            server_id: self.server_id,
            message_type: MessageType::Text,
            group_code: self.group_code,
            session_id: 0,
            content: self.content,
            ref_type: None,
            ref_message_ids: None,
            ext: None,
            ext1: None,
            ext2: None,
            version: 0,
            status: ImMessageStatus::wrap(false, &self.status),
            file_status: ImMessageFileStatus::wrap(false, &self.file_status),
            action_status: ImMessageActionStatus::wrap(false, &self.action_status),
            server_receive_time: Some(self.create_date_time),
            create_date_time: Local::now(),
            update_date_time: Local::now(),
            to_user_id: self.to_user_id,
            message_send_set: None,
            session: None,
        }
    }
}

impl ImMessageStatus {
    pub fn wrap(is_sender: bool, message_status: &MessageStatus) -> ImMessageStatus {
        match message_status {
            MessageStatus::None => { ImMessageStatus::None }
            MessageStatus::Receive => {
                if is_sender {
                    ImMessageStatus::Readed
                } else {
                    ImMessageStatus::Sended
                }
            }
            MessageStatus::Readed => { ImMessageStatus::Readed }
            MessageStatus::Withdrawed => { ImMessageStatus::Withdrawed }
            MessageStatus::Delete => { ImMessageStatus::Delete }
            MessageStatus::Updated => { ImMessageStatus::Updated }
            MessageStatus::UserDelete => { ImMessageStatus::Delete }
        }
    }
}

impl MessageStatus {
    fn wrap(is_sender: bool, message_status: &MessageStatus) -> ImMessageStatus {
        match message_status {
            MessageStatus::None => { ImMessageStatus::None }
            MessageStatus::Receive => { ImMessageStatus::Sended }
            MessageStatus::Readed => { ImMessageStatus::Sended }
            MessageStatus::Withdrawed => { ImMessageStatus::Withdrawed }
            MessageStatus::Delete => { ImMessageStatus::ServerDeleted }
            MessageStatus::Updated => { ImMessageStatus::Updated }
            MessageStatus::UserDelete => { ImMessageStatus::Delete }
        }
    }
}

impl ImMessageFileStatus {
    fn wrap(is_sender: bool, message_file_status: &Option<MessageFileStatus>) -> ImMessageFileStatus {
        if message_file_status.is_none() {
            return ImMessageFileStatus::None;
        }

        let message_file_status = message_file_status.as_ref().unwrap();
        match message_file_status {
            MessageFileStatus::None => { ImMessageFileStatus::None}
            MessageFileStatus::Uploaded => {
                if is_sender {
                    ImMessageFileStatus::Uploaded
                } else {
                    ImMessageFileStatus::Downloaded
                }
            }
            MessageFileStatus::Downloading => {
                if is_sender {
                    ImMessageFileStatus::Downloaded
                } else {
                    ImMessageFileStatus::Uploaded
                }
            }
            MessageFileStatus::Downloaded => {
                if is_sender {
                    ImMessageFileStatus::Downloaded
                } else {
                    ImMessageFileStatus::Uploaded
                }
            }
        }
    }
}


impl ImMessageActionStatus {
    fn wrap(_is_sender: bool, action_status: &MessageActionStatus) -> ImMessageActionStatus {
        match action_status {
            MessageActionStatus::None => { ImMessageActionStatus::None }
            MessageActionStatus::Readed => { ImMessageActionStatus::Readed }
            MessageActionStatus::Withdrawed => { ImMessageActionStatus::Withdrawed }
            MessageActionStatus::Delete => { ImMessageActionStatus::Delete }
            MessageActionStatus::Updated => { ImMessageActionStatus::None }
            MessageActionStatus::UserDelete => { ImMessageActionStatus::Delete }
        }
    }
}

impl From<&MessageActionItem> for MessageActionOkItem {
    fn from(value: &MessageActionItem) -> Self {
        Self {
            message_id: value.message_id.clone(),
            user_id: value.user_id.clone(),
        }
    }
}

impl From<&ImMessage> for MessageObject {
    fn from(value: &ImMessage) -> Self {
        let ref_type = match value.ref_type.clone() {
            None => {None}
            Some(value) => { Some(MessageRefType::from(&value)) }
        };
        Self {
            message_type: value.message_type.clone(),
            from_user_id: value.from_user_id.clone(),
            content: value.content.clone(),
            server_id: value.server_id.clone(),
            session_id: Some(value.session_id.clone().to_string()),
            group_code: value.group_code.clone(),
            to_user_id: value.to_user_id.clone(),
            ref_type,
            ref_message_ids: value.ref_message_ids.clone(),
            status: MessageStatus::None,
            file_status: None,
            action_status: MessageActionStatus::None,
            user_send_info_set: None,
            create_date_time: Local::now(),
            local_seq: value.client_id.clone(),
        }
    }
}

impl From<&ImMessageRefType> for MessageRefType {
    fn from(value: &ImMessageRefType) -> Self {
        match value {
            ImMessageRefType::Ref => { MessageRefType::Ref }
            ImMessageRefType::Transfer => {MessageRefType::Transfer }
        }
    }
}